package org.bling.star.client.configuration;

import org.bling.star.client.connect.ConnectWatcher;
import org.bling.star.client.connect.ClientConnection;
import org.bling.star.client.server.reciver.BusinessService;
import org.bling.star.common.enums.EnvironmentConstant;
import org.bling.star.common.enums.ServerType;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.bling.star.client.server.reciver.BusinessServiceImpl;
@Configuration
@PropertySource("classpath:application.yml")
@Slf4j
public class TalkingClientConfig {
    private String host = "127.0.0.1";
    private Integer port = 9999;
    private ServerType serverType;

    public TalkingClientConfig(Environment environment) throws Exception {
        host = environment.getProperty(EnvironmentConstant.LOCAL_HOST, String.class);
        port = environment.getProperty(EnvironmentConstant.LOCAL_PORT, Integer.class);
        if(host == null || host == "") {
            host = "127.0.0.1";
        }
        if(port == null ) {
            port = 9999;
        }

        this.host = host;
        this.port = port;
    }
    @Bean
    public String host() {return this.host;}
    @Bean
    public Integer port() {return this.port;}
    @Bean
    public ClientConnection clientConnection() {
        Bootstrap bootstrap = new Bootstrap();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ChannelFuture connect = null;
        try {
            connect = bootstrap.group(workerGroup).
                    channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,128)
                    .option(ChannelOption.SO_KEEPALIVE,true)  // 保持长连接
                    .handler(new ChannelInitializer<Channel>() {
                        @Override
                        protected void initChannel(Channel ch) throws Exception {
                            ch.pipeline().
                                    addLast(new ObjectDecoder(10240, ClassResolvers.cacheDisabled(this.getClass().getClassLoader()))).
                                    addLast(new ConnectWatcher()).
                                    addLast(new BusinessHandler(businessService())).
                                   // addLast(new IdleStateHandler( 0, 0, 60)).
                                    addLast(new ObjectEncoder());
                        }
                    }).connect(host, port).sync();

            log.info("客户端启动,host:{},port:{},channel:{}",host,port,connect.channel());
            ChannelFuture future = connect.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                        // 连接成功
                        log.error("Connected to " + host + ":" + port);
                    } else {
                        // 连接失败
                        log.error("Connection attempt failed: " + future.cause());
                    }
                }});
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        ChannelFuture finalConnect = connect;
        Runtime.getRuntime().addShutdownHook(new Thread(()->{
            if(finalConnect != null) {
                finalConnect.channel().close();
            }
            if(bootstrap != null) {
                workerGroup.shutdownGracefully();
            }
        }));
        return new ClientConnection(connect.channel());
    }

    @Bean
    public BusinessService businessService(){
        return new BusinessServiceImpl();
    }
}
